import java.awt.geom.*;
import java.awt.*;
/**
 * Clase del objeto gráfico del resorte que hereda de la clase de su implementación
 * Spring e implementa la interfaz Drawable.
 * @version 2
 */
class GSpring extends Spring implements Drawable {
   private static final double xPoints[]={0,0.10, 0.125, 0.175, 0.225, 0.275, 0.325, 
                                          0.375, 0.425, 0.475, 0.525,0.575,0.625,
                                          0.675,0.725,0.775,0.825,0.875, 0.90,1.0};
   private static final double yPoints[]={0,0,-0.1,0.1,-0.1,0.1,-0.1,0.1,-0.1,0.1,
                                          -0.1,0.1,-0.1,0.1,-0.1,0.1,-0.1,0.1,0,0};
   private static final Path2D.Double polyline = 
                      new Path2D.Double(Path2D.WIND_EVEN_ODD,xPoints.length);
   private Path2D.Double shape;
   private float stiffness; // agregado
   private Stroke stroke;
   private Vector2D freeAendPosition;    // to draw a spring we need
   private Vector2D freeBendPosition;  // extremes well definied
                                     // when it is not connected.

   static {  // static initialization block. It creates a spring of length = 1.
      polyline.moveTo (xPoints[0], yPoints[0]);
      for (int index = 1; index < xPoints.length;index++)
         polyline.lineTo(xPoints[index], yPoints[index]);
   }
   /**
    * Constructor del resorte con sus datos iniciales
    * @param restLength largo del resorte.
    * @param stiffness constante del resorte.
    */
   public GSpring(float restLength, float stiffness) {
      super(restLength, stiffness);
      freeAendPosition = new Vector2D(0,0);
      freeBendPosition = new Vector2D(restLength,restLength);
      AffineTransform at = AffineTransform.getTranslateInstance(0,0);
      Vector2D v = getVector();
      at.rotate(v.getX(), v.getY());
      at.scale(v.module(), restLength);
      shape = (Path2D.Double) at.createTransformedShape(polyline);
      stroke = new BasicStroke(1);
      this.stiffness = stiffness; // agregado
   }
   /**
    * Función para obtener la posición del extremo A del resorte
    * @return vector de posición del extremo A del resorte.
    */
   public Vector2D getAendPosition() {
      if (a_end == null)
         return freeAendPosition;
      return super.getAendPosition();
   }
   /**
    * Función para obtener la posición del extremo B del resorte
    * @return vector de posición del extremo B del resorte.
    */
   public Vector2D getBendPosition() {
      if (b_end == null)
         return freeBendPosition;
      return super.getBendPosition();
   }
   /**
    * Función que dibuja el resorte con sus datos.
    * @param g lienzo gráfico en 2 dimensiones para dibujar.
    */
   public void draw (Graphics2D g){
      Vector2D a=getAendPosition();
      Vector2D b=getBendPosition(); // agregado
      double ax = a.getX();
      double ay = a.getY();
      double bx = b.getX(); // agregado
      double by = b.getY(); // agregado
      Vector2D v = getVector();
      AffineTransform at = AffineTransform.getTranslateInstance(ax, ay);
      at.rotate(v.getX(), v.getY());
      at.scale(v.module(),  restLength);
      shape = (Path2D.Double) at.createTransformedShape(polyline);
      if (v.module() < restLength)
         g.setColor(Color.BLACK);
      else
         g.setColor(Color.RED);
      g.setStroke(stroke);
      g.draw(shape);
      g.setColor(Color.blue); // agregado
      g.drawString(Float.toString(stiffness), (int)(ax+bx)/2, (int)(ay+by)/2); // agregado      
   }
   /**
    * Función para consultar si el punto está dentro del dibujo del resorte.
    * @param x coordenada X.
    * @param y coordenada Y
    * @return estado si está o no incluido.
    */
   public boolean contains(int x, int y){
      return shape.getBounds2D().contains(x,y);
   }
   /**
    * Función para desacoplar un extremo del resorte.
    * @param x coordenada X.
    * @param y coordenada Y.
    */
   public void dragTo(int x, int y){
      Vector2D a=getAendPosition();
      Vector2D b=getBendPosition();
      double da = Math.abs(a.getX()-x)+Math.abs(a.getY()-y); // "distance" to a
      double db = Math.abs(b.getX()-x)+Math.abs(b.getY()-y); // "distance" to a
      if (da < db) {
         detachAend();
         freeAendPosition.set(x,y);
      }
      else {
         detachBend();
         freeBendPosition.set(x,y);
      }
   }
   /**
    * Función de actualización del estado del resorte.
    */
   public void updateState(){  // just to return to a rest length
      if (a_end==null && b_end==null) return;  // when it is released
      if (a_end!=null) {
         Vector2D v = getVector().unitary().times(restLength);
         freeBendPosition = getAendPosition().plus(v);
         return;
      }
      if (b_end!=null) {
         Vector2D v = getVector().unitary().times(restLength);
         freeAendPosition = getBendPosition().minus(v);
         return;
      }
   }
   /**
    * Función que cambia el grosor de la línea a 3.
    */
   public void setSelected() {
      stroke = new BasicStroke(3);
   }
   /**
    * Función que cambia el grosor de la línea a 1.
    */
   public void setReleased() {
      stroke = new BasicStroke(1);
   }
}